package edu.hawaii.halealohacli.kmj;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.wattdepot.client.WattDepotClient;

/**
 * Runs a series of test cases for the SetBaseline class.
 * 
 * @author Jordan Takayama
 */
public class TestSetBaseline {

  /**
   * The URL of the WattDepot server.
   */
  private String url = "http://server.wattdepot.org:8190/wattdepot/";

  /**
   * A bad URL to a WattDepot server. Used to trigger exceptions.
   */
  private String badUrl = "http://server.wattdepot.org:8190/wattdepot/null";
  
  /**
   * A WattDepot client which connects to the server.
   */
  private WattDepotClient sampleClient = new WattDepotClient(url);

  /**
   * A WattDepotClient which will always fail to connect to a server.
   */
  private WattDepotClient fakeClient = new WattDepotClient(badUrl);
  
  /**
   * A SetBaseline object which is initialized with specific data for each test case.
   */
  private SetBaseline testObject = null;
  
  /**
   * A default location name to use in testing.
   */
  private String sourceName = "Lehua";

  /**
   * A second location name to use in testing.
   */
  private String altSourceName = "Mokihana";
  
  /**
   * A default baseline request date to use in testing. In the event of a server crash (or switching
   * to a different server) developers may need to change this date to a valid one to compensate for
   * the unavailability of data for this date. The current value of testDate is "2011-12-01".
   */
  private String testDate = "2011-12-01";
  
  /**
   * Tests the setBaseline constructor.
   * 
   * @throws Exception If a method call within the test throws an exception.
   */
  @Test
  public void testSetBaseline() throws Exception {
   // Trigger an exception by passing a bad WattDepotClient as a parameter.
   System.out.println("Testing SetBaseline constructor:");
   try {
     testObject = new SetBaseline(fakeClient, sourceName, testDate);
   }
   catch (Exception e) {
     System.out.println("Correctly responded to being unable to connect to WattDepotClient by " 
         + "throwing exception:\n" + e.getMessage());
   }
   testObject = new SetBaseline(sampleClient, sourceName, testDate);
   assertNotNull("SetBaseline constructor returned null.", testObject);
  }

  /**
   * Tests the getter for the Baseline object.
   * 
   * @throws Exception  If a method call within the test throws an exception.
   */
  @Test
  public void testGetBaselineData() throws Exception {
    Baseline same = new Baseline(sampleClient, sampleClient.getSource(sourceName), testDate);
    testObject = new SetBaseline(sampleClient, sourceName, testDate);
    Baseline testBaseline = testObject.getBaselineData();
    double sameValues[] = same.getBaselineValues();
    double testValues[] = testBaseline.getBaselineValues();
    boolean sameBaselineData = true;
    boolean baselinesEqual = false;
    
    System.out.println("Testing getBaselineData:");
    // Compare the two Baselines field by field.
    for (int i = 0; i < testValues.length; i++) {
      if (!(sameValues[i] == testValues[i])) {
          sameBaselineData = false;
      }
    }
    if (same.getBaselineDate().equals(testBaseline.getBaselineDate()) &&
        same.getSourceName().equals(testBaseline.getSourceName()) && sameBaselineData) {
      baselinesEqual = true;
    }
    assertTrue("getBaselineData should return a Baseline with the same information as " 
        + "a Baseline created with the same parameters", baselinesEqual);
  }

  /**
   * Tests the setter for the Baseline object.
   * 
   * @throws Exception If a method call within the test throws an exception.
   */
  @Test
  public void testSetBaselineData() throws Exception {
    // Get sample Baseline data to use with setBaselineData.
    Baseline setterBaseline = new Baseline(sampleClient, sampleClient.getSource(altSourceName), 
        testDate);
    double[] setValues = setterBaseline.getBaselineValues();
    Baseline testBaseline;
    double[] testValues;
    boolean sameBaselineData = true;
    boolean baselinesEqual = false;
    testObject = new SetBaseline(sampleClient, sourceName, testDate);
    testObject.setBaseline(setterBaseline);
    testBaseline = testObject.getBaselineData();
    testValues = testBaseline.getBaselineValues();
    
    System.out.println("Testing setBaselineData:");
    // Compare the two Baselines field by field.
    for (int i = 0; i < testValues.length; i++) {
      if (!(setValues[i] == testValues[i])) {
          sameBaselineData = false;
      }
    }
    if (setterBaseline.getBaselineDate().equals(testBaseline.getBaselineDate()) &&
        setterBaseline.getSourceName().equals(testBaseline.getSourceName()) && sameBaselineData) {
      baselinesEqual = true;
    }
    assertTrue("Set Baseline should be the same as the Baseline passed to setBaselineData", 
        baselinesEqual);
  }

  /**
   * Checks that the printResult method can be called without throwing exceptions.
   * 
   * @throws Exception  If a method call within this method, other than the call to printResult,
   * throws an Exception.
   */
  @Test
  public void testPrintResult() throws Exception {
    testObject = new SetBaseline(sampleClient, sourceName, testDate);
    try {
      System.out.println("Testing printResult.");
      testObject.printResult();
    }
    catch (Exception e) {
      fail("Exception occurred while running printResult:\n" + e.getMessage());
    }
  }
}
